import { ref, onBeforeUnmount } from "vue";
import { fetchEventSource } from "@microsoft/fetch-event-source";

// 自定义错误类型
/** 不可恢复错误：4xx(除429)/格式错/刷新令牌失败 */
export class FatalError extends Error {
  readonly status?: number;
  readonly code?: string;
  constructor(message: string, status?: number, code?: string) {
    super(message);
    this.name = "FatalError";
    this.status = status;
    this.code = code;
  }
}

/** 可重试错误：网络抖动、5xx、429 限流、502 网关 */
export class RetryableError extends Error {
  readonly status?: number;
  readonly retryAfter?: number; // 后端给的秒数
  constructor(message: string, status?: number, retryAfter?: number) {
    super(message);
    this.name = "RetryableError";
    this.status = status;
    this.retryAfter = retryAfter;
  }
}

/** 业务逻辑错误：后端返回 {"code": 3001, "msg": "敏感词"} */
export class BizError extends Error {
  readonly code: number;
  constructor(code: number, msg: string) {
    super(msg);
    this.name = "BizError";
    this.code = code;
  }
}

export interface SSEOptions {
  url: string;
  method?: "GET" | "POST";
  headers?: Record<string, string>;
  body?: any;
  /* 最大重试次数，默认3次 */
  maxRetries?: number;
  /* 退避基数 ms，默认 1000 */
  backoffBase?: number;
  /** 收到一条消息时的回调 */
  onMessage: (data: any) => void;
  /** 连接建立成功回调 */
  onOpen?: (res: Response) => void;
  /** 连接正常关闭回调 */
  onClose?: () => void;
  /** 发生错误（含网络、解析、用户 abort）回调 */
  onError?: (err: any) => void;
  /** 是否页面隐藏时继续连接，默认 true */
  openWhenHidden?: boolean;
}

export function useSSE(opts: SSEOptions) {
  const abortController = new AbortController();
  // 连接是否已结束（含用户手动 abort）
  const isClosed = ref(false);
  const maxRetries = opts.maxRetries ?? 3;
  const backoffBase = opts.backoffBase ?? 1000;
  const retryCount = ref(0);

  /* 设置超时时间，否则请求会一直挂着 */
  let timeoutId: number | null = null;
  const TIMEOUT = 60_000; // 60 秒总超时

  const clearTimeout = () => {
    if (timeoutId) {
      window.clearTimeout(timeoutId);
      timeoutId = null;
    }
  };

  const startDataTimeout = () => {
    clearTimeout();
    timeoutId = window.setTimeout(() => {
      throw new RetryableError("SSE timeout 60s");
    }, TIMEOUT);
  };

  const sleep = (ms: number) => new Promise(r => setTimeout(r, ms));

  const start = async () => {
    let fatalErrorInOpen: FatalError | BizError | null = null;
    while (retryCount.value <= maxRetries && !abortController.signal.aborted) {
      try {
        clearTimeout();
        await fetchEventSource(opts.url, {
          method: opts.method || "GET",
          headers: {
            "Content-Type": "application/json",
            Accept: "text/event-stream",
            ...opts.headers,
          },
          body: opts.body ? JSON.stringify(opts.body) : undefined,
          signal: abortController.signal,
          openWhenHidden: opts.openWhenHidden ?? true,

          async onopen(res) {
            startDataTimeout();
            const contentType = res.headers.get("content-type") || "";
            // 接口返回数据格式不正确
            // if (!contentType.includes("text/event-stream")) {
            //   throw new FatalError(`Invalid content-type: ${res}`);
            // }
            // 登录失效
            if (res.status === 401) {
              // await logout();
              throw new FatalError("Unauthorized", res.status);
            }
            if (res.status >= 500) {
              throw new RetryableError(`Server ${res.status}`, res.status);
            }
            retryCount.value = 0;
            opts.onOpen?.(res);
          },

          onmessage(evt) {
            startDataTimeout(); // 收到真实数据就清掉超时器
            if (fatalErrorInOpen) {
              throw fatalErrorInOpen;
            }

            try {
              const json = JSON.parse(evt.data);
              if (json.error) {
                // 后端约定：{"error": {"code": 3001, "msg": "敏感词"}}
                throw new BizError(json.error.code, json.error.msg);
              }
              opts.onMessage(json);
            } catch (e) {
              if (e instanceof BizError) throw e; // 抛给外层 catch
              console.warn("[SSE] parse error", e);
            }
          },

          onclose() {
            clearTimeout();
            isClosed.value = true;
            opts.onClose?.();
          },

          onerror(err) {
            clearTimeout();
            // 致命错误：让 fetchEventSource 停止重连
            if (err instanceof FatalError || err instanceof BizError) {
              throw err; // 关键：继续抛，库会终止
            }
            // 可重试错误：库默认会退避重连，这里直接 return 即可
          },
        });
        break;
      } catch (error: any) {
        clearTimeout();
        // 用户手动取消
        if (abortController.signal.aborted) {
          isClosed.value = true;
          return;
        }
        // 不可恢复错误
        if (error instanceof FatalError || error instanceof BizError) {
          isClosed.value = true;
          opts.onError?.(error);
          return;
        }
        // 可重试错误
        if (error instanceof RetryableError) {
          if (retryCount.value >= maxRetries) {
            isClosed.value = true;
            opts.onError?.(new FatalError("Max retries reached"));
            return;
          }
          const delay = Math.min(backoffBase * 2 ** retryCount.value, 30000); // 上限 30s
          retryCount.value++;
          opts.onError?.(error); // 通知 UI
          await sleep(delay);
          continue;
        }
      }
    }
  };

  // 外部手动取消
  const abort = () => {
    if (!abortController.signal.aborted) {
      clearTimeout();
      abortController.abort();
      isClosed.value = true;
      console.log("会话被取消");
    }
  };

  // 组件卸载时自动取消
  onBeforeUnmount(abort);

  return { start, abort, isClosed };
}
